package com.yn.xgame;

import com.alibaba.fastjson.JSON;
import com.yn.xgame.util.Utils;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.List;

/**
 * ZkClient
 * Created by wangboo on 2017/7/12.
 */
public class ZkClient {

    private static final Logger logger = LoggerFactory.getLogger(ZkClient.class);

    private ZooKeeper zkClient;
    private static final byte[] EMPTY_BIN = new byte[]{};

    public ZkClient() {
    }

    public void connect(String address, Watcher watcher) throws IOException {
        zkClient = new ZooKeeper(address, 50_000, watcher);
        init();
    }

    private void init() {
        checkPath("");
        checkPath("/access");
        checkPath("/gate");
        checkPath("/logic");
    }

    public void checkPath(String key) {
        checkPath(key, false);
    }

    public void checkPath(String key, boolean watch) {
        if (zkClient == null) return;
        String fullKey = getFullPath(key);
        try {
            Stat stat = zkClient.exists(fullKey, watch);
            if (stat == null) {
                zkClient.create(fullKey, EMPTY_BIN, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
        } catch (Exception e) {
            logger.error("createOrsetData error: ", e);
        }
    }

    public void createOrsetData(String key, Object obj) {
        createOrsetData(key, obj, false);
    }

    public void createOrsetData(String key, Object obj, boolean watch) {
        if (zkClient == null) return;
        String fullKey = getFullPath(key);
        byte[] bin = JSON.toJSONBytes(obj);
        try {
            Stat stat = zkClient.exists(fullKey, watch);
            if (stat == null) {
                zkClient.create(fullKey, bin, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            } else {
                zkClient.setData(fullKey, bin, -1);
            }
        } catch (Exception e) {
            logger.error("createOrsetData error: ", e);
        }
    }

    public void createOrsetData_EPHEMERAL(String key, Object obj) {
        createOrsetData_EPHEMERAL(key, obj, true);
    }
    public void createOrsetData_EPHEMERAL(String key, Object obj, boolean jsonfy) {
        if (zkClient == null) return;
        String fullKey = getFullPath(key);
        byte[] bin;
        if (jsonfy) {
            bin = JSON.toJSONBytes(obj);
        } else {
            bin = obj.toString().getBytes(Utils.charset);
        }
        try {
            Stat stat = zkClient.exists(fullKey, false);
            logger.debug("createOrsetData_EPHEMERAL: {}, {}", fullKey, new String(bin));
            if (stat == null) {
                zkClient.create(fullKey, bin, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
            } else {
                zkClient.setData(fullKey, bin, -1);
            }
        } catch (Exception e) {
            logger.error("createOrsetData error: ", e);
        }
    }

    public String getDataAsString(String path, Watcher watcher) {
        String fullPath = getFullPath(path);
        try {
            byte[] bin = zkClient.getData(fullPath, watcher, null);
            return new String(bin, Utils.charset);
        } catch (Exception e) {
            logger.error("getDataAsString error: ", e);
        }
        return null;
    }

    public <T> T getData(String key, Class<T> clazz) {
        if (zkClient == null) return null;
        String fullKey = getFullPath(key);
        try {
            byte[] bin = zkClient.getData(fullKey, true, null);
            return JSON.parseObject(bin, clazz);
        } catch (Exception e) {
            logger.error("getData error: ", e);
        }
        return null;
    }

    public List<String> getChildren(String key) {
        return getChildren(key, null);
    }

    public List<String> getChildren(String key, Watcher watcher) {
        if (zkClient == null) return null;
        String fullKey = getFullPath(key);
        try {
            checkPath(fullKey);
            return zkClient.getChildren(fullKey, watcher);
        } catch (Exception e) {
            logger.error("getChildren error: ", e);
        }
        return null;
    }

    public void shutdown() {
        if (zkClient != null) {
            try {
                zkClient.close();
            } catch (InterruptedException e) {
                logger.error("error: ", e);
            }
        }
    }

    private String getFullPath(String key) {
        if (key.startsWith(GlobalSetting.ZK_PREFIX)) {
            return key;
        }
        return GlobalSetting.ZK_PREFIX + key;
    }


    public void reconnect() {

    }
}
